﻿#include<iostream>
#include<memory>//智能指针头文件
using namespace std;

//智能指针的目的：解决内存泄漏问题
//设计思路——RAII：⼀种管理资源的类的设计思想
//本质是一种利⽤对象生命周期来管理获取到的动态资源，避免资源泄漏
//在获取资源时把资源委托给⼀个对象，接着控制对资源的访问，
//资源在对象的生命周期内始终保持有效，最后在对象析构的时候释放资源，这样保障了资源的正常释放，避免资源泄漏问题

//解决在抛异常中内存泄漏问题
//template<class T>
//class SmartPtr
//{
//public:
//	// RAII
//	SmartPtr(T* ptr)
//		:_ptr(ptr)
//	{}
//
//	~SmartPtr()
//	{
//		cout << "delete[] " << _ptr << endl;
//		delete[] _ptr;
//	}
//	// 重载运算符，模拟指针的行为，⽅便访问资源
//	T& operator*()
//	{
//		return *_ptr;
//	}
//
//	T* operator->()
//	{
//		return _ptr;
//	}
//
//	T& operator[](size_t i)
//	{
//		return _ptr[i];
//	}
//private:
//	T* _ptr;
//};
//
//double Divide(int a, int b)
//{
//	// 当b == 0时抛出异常
//	if (b == 0)
//	{
//		throw "Divide by zero condition!";
//	}
//	else
//	{
//		return (double)a / (double)b;
//	}
//}
//
//void Func()
//{
//	// 这⾥使⽤RAII的智能指针类管理new出来的数组以后，程序简单多了
//	//智能指针会自动释放资源
//	SmartPtr<int> sp1 = new int[10];//一个对象在程序结束时是一定会调用析构函数将他的资源释放(系统规定的)
//	SmartPtr<int> sp2 = new int[10];
//	for (size_t i = 0; i < 10; i++)
//	{
//		sp1[i] = sp2[i] = i;
//	}
//	int len, time;
//	cin >> len >> time;
//	cout << Divide(len, time) << endl;
//}
//
//int main()
//{
//	try
//	{
//		Func();
//	}
//	catch (const char* errmsg)
//	{
//		cout << errmsg << endl;
//	}
//	catch (const exception& e)
//	{
//		cout << e.what() << endl;
//	}
//	catch (...)
//	{
//		cout << "未知异常" << endl;
//	}
//	return 0;
//}


struct Date
{
	int _year;
	int _month;
	int _day;
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}
	~Date()
	{
		cout << "~Date()" << endl;
	}
};

//使用
//int main()
//{
//	//auto_ptr:自动指针(C++98)，强烈不建议使用
//	auto_ptr<Date> ap1(new Date);
//	// 拷贝时，管理权限转移，被拷贝对象ap1悬空
//	auto_ptr<Date> ap2(ap1);
//
//	// 空指针访问，ap1对象已经悬空
//	//ap1->_year++;//ap1就为空，但它仍然可以被调用，就会报错
//
//	//unique_ptr:唯一指针(C++11),不支持构造，支持移动
//	//不需要拷贝的时候建议使用
//	unique_ptr<Date> up1(new Date);
//	// 不支持拷贝
//	//unique_ptr<Date> up2(up1);
//	// 支持移动，但是移动后up1也悬空，所以使⽤移动要谨慎	
//	unique_ptr<Date> up3(move(up1));//使用完后up1就为空了
//
//	//shared_ptr：共享指针(C++11)
//	//底层实现：引用计数
//	//需要拷贝的时候建议使用
//	shared_ptr<Date> sp1(new Date);
//	// 支持拷贝
//	shared_ptr<Date> sp2(sp1);
//	shared_ptr<Date> sp3(sp2);
//
//
//	return 0;
//}

#include"shared_ptr.h"
//原理
//int main()
//{
//	yyc::shared_ptr<Date> sp1(new Date);
//	yyc::shared_ptr<Date> sp2(sp1);
//	yyc::shared_ptr<Date> sp3(new Date);
//	//sp3 = sp2;
//	sp2 = sp3;
//
//
//	return 0;
//}

//删除器
template<class T>
void DeleteArrayFunc(T* ptr)
{
	delete[] ptr;
}

template<class T>
class DeleteArray
{
public:
	void operator()(T* ptr)
	{
		delete[] ptr;
	}
};

class Fclose
{
public:
	void operator()(FILE* ptr)
	{
		cout << "fclose:" << ptr << endl;
		fclose(ptr);
	}
};

//int main()
//{
//	//进行delete[]
//	//1、
//	/*std::shared_ptr<Date[]> sp1(new Date);
//	std::unique_ptr<Date[]> sp1(new Date);*/
//
//	//2、定制删除器：函数指针/仿函数/lambda，用包装器
//	//shared_ptr在构造函数传
//	std::shared_ptr<Date> sp1(new Date[10], DeleteArray<Date>());//仿函数
//	std::shared_ptr<Date> sp2(new Date[10], DeleteArrayFunc<Date>);//函数指针
//	auto delArrOBJ = [](Date* ptr) {delete[] ptr; };
//	std::shared_ptr<Date> sp4(new Date[5], delArrOBJ);//lambda
//
//	//unique_ptr必须在类模板实例化时传
//	unique_ptr<Date, DeleteArray<Date>> up2(new Date[5]);//仿函数
//	unique_ptr<Date, void(*)(Date*)> up3(new Date[5], DeleteArrayFunc<Date>);//函数指针
//	unique_ptr<Date, decltype(delArrOBJ)> up4(new Date[5], delArrOBJ);//lambda
//	//decltype：推导类型
//
//	// 实现其他资源管理的删除器
//	shared_ptr<FILE> sp5(fopen("Test.cpp", "r"), Fclose());
//	shared_ptr<FILE> sp6(fopen("Test.cpp", "r"), [](FILE* ptr) {
//		cout << "fclose:" << ptr << endl;
//		fclose(ptr);
//		});
//
//	return 0;
//}

//int main()
//{
//	shared_ptr<Date> sp1(new Date(2024, 9, 11));
//	shared_ptr<Date> sp2 = make_shared<Date>(2024, 9, 11);//效率高，避免内存碎片化
//
//	shared_ptr<Date> sp4;
//	// if (sp1.operator bool())
//	if (sp1)
//		cout << "sp1 is not nullptr" << endl;
//	if (!sp4)
//		cout << "sp1 is nullptr" << endl;
//	// 报错：在构造函数前加上explicit
//	/*shared_ptr<Date> sp5 = new Date(2024, 9, 11);
//	unique_ptr<Date> sp6 = new Date(2024, 9, 11);*/
//
//	return 0;
//}

//循环引用
struct ListNode
{
	int _data;
	/*std::shared_ptr<ListNode> _next;
	std::shared_ptr<ListNode> _prev;*/
	// 这⾥改成weak_ptr，当n1->_next = n2;绑定shared_ptr时
	// 不增加n2的引⽤计数，不参与资源释放的管理，就不会形成循环引⽤了
	yyc::weak_ptr<ListNode> _next;
	yyc::weak_ptr<ListNode> _prev;
	~ListNode()
	{
		cout << "~ListNode()" << endl;
	}
};

int main()
{
	// 循环引用 -- 内存泄露
	yyc::shared_ptr<ListNode> n1(new ListNode);
	yyc::shared_ptr<ListNode> n2(new ListNode);
	cout << n1.use_count() << endl;
	cout << n2.use_count() << endl;
	//互相指向的时候就要使用weak_ptr
	n1->_next = n2;
	n2->_prev = n1;

	cout << n1.use_count() << endl;
	cout << n2.use_count() << endl;

	// weak_ptr不支持管理资源，不支持RAII
	// weak_ptr是专门绑定shared_ptr，不增加他的引用计数，作为⼀些场景的辅助管理
	//std::weak_ptr<ListNode> wp(new ListNode);
	return 0;
}